架构图

项目搭建

原帖

准备工作建立module并设置依赖关系

model为模型层,api为接口层,core为核心层,app为界面层。

  • 四个模块之间的依赖设置为:model没有任何依赖,接口层依赖了模型层,核心层依赖了模型层和接口层,界面层依赖了核心层和模型层。
    然后建立模块之间的依赖关系
    建立module
第一步业务对象模型model
  • 封装业务逻辑,大部分都是从接口中传来的对象
    简单的bean,此处为CouponBO
第二步接口层封装api
  • 设计一种json返回的固定结构,如:
1
2
3
{"event": "0", "msg": "success"}
{"event": "0", "msg": "success", "obj":{...}}
{"event": "0", "msg": "success", "objList":[{...}, {...}], "currentPage": 1, "pageSize": 20, "maxCount": 2, "maxPage": 1}
  • 封装为实体类
    注意变量名需要和json的键名保持一致以方便解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ApiResponse<T> {
private String event; // 返回码,0为成功
private String msg; // 返回信息
private T obj; // 单个对象
private T objList; // 数组对象
private int currentPage; // 当前页数
private int pageSize; // 每页显示数量
private int maxCount; // 总条数
private int maxPage; // 总页数
// 构造函数,初始化code和msg
public ApiResponse(String event, String msg) {
this.event = event;
this.msg = msg;
}
// 判断结果是否成功
public boolean isSuccess() {
return event.equals("0");
}
// TODO 所有属性的getter和setter
}
  • 对应的请求接口,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public interface Api {
// 发送验证码
public final static String SEND_SMS_CODE = "service.sendSmsCode4Register";
// 注册
public final static String REGISTER = "customer.registerByPhone";
// 登录
public final static String LOGIN = "customer.loginByApp";
// 券列表
public final static String LIST_COUPON = "issue.listNewCoupon";
/**
* 发送验证码 --传入的T为Void
* @param phoneNum 手机号码
* @return 成功时返回:{ "event": "0", "msg":"success" }
*/
public ApiResponse<Void> sendSmsCode4Register(String phoneNum);
/**
* 注册
* @param phoneNum 手机号码
* @param code 验证码
* @param password MD5加密的密码
* @return 成功时返回:{ "event": "0", "msg":"success" }
*/
public ApiResponse<Void> registerByPhone(String phoneNum, String code, String password);
/**
* 登录
* @param loginName 登录名(手机号)
* @param password MD5加密的密码
* @param imei 手机IMEI串号
* @param loginOS Android为1
* @return 成功时返回:{ "event": "0", "msg":"success" }
*/
public ApiResponse<Void> loginByApp(String loginName, String password, String imei, int loginOS);
/**
* 券列表 --传入的T为List<CouponBO>
* @param currentPage 当前页数
* @param pageSize 每页显示数量
* @return 成功时返回:{ "event": "0", "msg":"success", "objList":[...] }
*/
public ApiResponse<List<CouponBO>> listNewCoupon(int currentPage, int pageSize);
}
  • 然后就是api的具体实现方法ApiImpl
1
2
//传入参数进行网络请求相关的内容
public class ApiImpl implements Api { ... }

——此处还可把网络请求相关的内容放入另一个类中,如原作者写的HttpEngine类

设计思想:
1.网络请求作为一个单例来使用
2.抽取出请求的编码,等待超时时间,请求地址等一些常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class HttpEngine {
private final static String SERVER_URL = "http://uat.b.quancome.com/platform/api";
private final static String REQUEST_MOTHOD = "POST";
private final static String ENCODE_TYPE = "UTF-8";
private final static int TIME_OUT = 15000;
private static HttpEngine instance = null;
private HttpEngine() {
}
public static HttpEngine getInstance() {
if (instance == null) {
instance = new HttpEngine();
}
return instance;
}
public <T> T postHandle(Map<String, String> paramsMap, Type typeOfT) throws IOException {
String data = joinParams(paramsMap);
HttpUrlConnection connection = getConnection();
connection.setRequestProperty("Content-Length", String.valueOf(data.getBytes().length));
connection.connect();
OutputStream os = connection.getOutputStream();
os.write(data.getBytes());
os.flush();
if (connection.getResponseCode() == 200) {
// 获取响应的输入流对象
InputStream is = connection.getInputStream();
// 创建字节输出流对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 定义读取的长度
int len = 0;
// 定义缓冲区
byte buffer[] = new byte[1024];
// 按照缓冲区的大小,循环读取
while ((len = is.read(buffer)) != -1) {
// 根据读取的长度写入到os对象中
baos.write(buffer, 0, len);
}
// 释放资源
is.close();
baos.close();
connection.disconnect();
// 返回字符串
final String result = new String(baos.toByteArray());
Gson gson = new Gson();
return gson.fromJson(result, typeOfT);
} else {
connection.disconnect();
return null;
}
}
private HttpURLConnection getConnection() {
HttpURLConnection connection = null;
// 初始化connection
try {
// 根据地址创建URL对象
URL url = new URL(SERVER_URL);
// 根据URL对象打开链接
connection = (HttpURLConnection) url.openConnection();
// 设置请求的方式
connection.setRequestMethod(REQUEST_MOTHOD);
// 发送POST请求必须设置允许输入,默认为true
connection.setDoInput(true);
// 发送POST请求必须设置允许输出
connection.setDoOutput(true);
// 设置不使用缓存
connection.setUseCaches(false);
// 设置请求的超时时间
connection.setReadTimeout(TIME_OUT);
connection.setConnectTimeout(TIME_OUT);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Connection", "keep-alive");
connection.setRequestProperty("Response-Type", "json");
connection.setChunkedStreamingMode(0);
} catch (IOException e) {
e.printStackTrace();
}
return connection;
}
private String joinParams(Map<String, String> paramsMap) {
StringBuilder stringBuilder = new StringBuilder();
for (String key : paramsMap.keySet()) {
stringBuilder.append(key);
stringBuilder.append("=");
try { stringBuilder.append(URLEncoder.encode(paramsMap.get(key), ENCODE_TYPE));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
stringBuilder.append("&");
}
return stringBuilder.substring(0, stringBuilder.length() - 1);
}
}

第三步核心层逻辑

核心层处于接口层和界面层之间,向下调用Api,向上提供Action,它的核心任务就是处理复杂的业务逻辑

1
2
3
4
5
6
7
8
9
10
public interface AppAction {
// 发送手机验证码
public void sendSmsCode(String phoneNum, ActionCallbackListener<Void> listener);
// 注册
public void register(String phoneNum, String code, String password, ActionCallbackListener<Void> listener);
// 登录
public void login(String loginName, String password, ActionCallbackListener<Void> listener);
// 按分页获取券列表
public void listCoupon(int currentPage, ActionCallbackListener<List<CouponBO>> listener);
}

然后再去实现这些请求逻辑

1
public class AppActionImpl implements AppAction { ... }

参数为空,参数合法化 的这些检查都可放在此处检查,减少app模块逻辑里面不必要的混乱

将参数为空的检查、手机号有效性的检查、数字型范围的检查等等,都可以抽成独立的方法,从而减少重复代码的编写。异步任务里的代码也一样,都是可以通过重构优化的。另外,需要扩展时,比如添加缓存,那就在调用Api之前处理。

第四步 界面层app

  • 界面层需要调用核心层的Action,而这会在整个应用级别都用到,因此,Action的实例最好放在Application里
  • 一个Activity的基类
  • 一个抽象的适配器基类